<?php
namespace Link;

use PHPExcel\IOFactory;

/**
 * 检测文件中的链接是否有效
 */
class ValidLink
{
  // 需要检测的关键字
  private $_validWord  = '';

  // 输入文件路径
  private $_inputFile  = '';

  // 输出文件路径
  private $_outputFile = '';

  // 请求失败列表
  private $_failList  = '';

  // 文件加载器
  private $_objLoader = null;

  /**
   * 标准读入
   */
  public function read($prompt = '')
  {
      fwrite(STDOUT, $prompt);
      $line = trim(fgets(STDIN));
      return $line;
  }


  /**
   * 读入文件
   */
  public function import($source = '')
  {
    is_readable($source) || die('文件读取失败'.PHP_EOL);

    $info = pathinfo($source);
    $target = "{$info['dirname']}/{$info['filename']}_new.{$info['extension']}";
    $this->_outputFile = $target;
    copy($source, $target);

    $loader = \PHPExcel_IOFactory::load($source);
    if (empty($loader)) {
        die('文件加载失败'.PHP_EOL);
    }
    $this->_objLoader = $loader;
  }


  /**
   * 运行
   */
  public function run()
  {
      // 输入文件
      $path = $this->read('文件输入路径(./data/datas.xls):');
      $path = empty($path)? './data/datas.xls' : $path;
      $this->_inputFile  = $path;
      $this->import($path);

      // 检索词语
      $word = $this->read('检索的关键字:');
      $word = empty($word) ? '叶简明' : $word;
      $this->_validWord = $word;

      // 从第几行开始检索
      $skip = $this->read('跳过几行(默认为1):');
      $skip = max($skip, 0);

      // 检测链接行
      $getLinkIndex = function($fields) {
          if (!is_array($fields)) {
              return false;
          }
          foreach ($fields as $key => $value) {
               $count = preg_match('/http[s]?:\/\//i', $value, $match);
               if ($count > 0) {
                   return $key;
               }
          }
          return false;
      };

      $datas = $this->_objLoader->getActiveSheet()->toArray();
      $index = $getLinkIndex($datas[$skip]);
      ($index !== false) || die('没有http链接'.PHP_EOL);


      $total = count($datas);
      foreach ($datas as $key => &$value) {
          if ($key < $skip) {
              continue;
          }

          $this->show_status(($key+1), $total);

          $url = $value[$index];
          $content = $this->http($url);
          $result  = $this->valid($content, $word);
          $value[] = $result ? '有效' : '无效';

          if (strpos($url, 'weibo') !== false) {
                if ($result) {
                    $profile = $this->weibo($content);
                } else {
                    $profile = array(0, 0, 0);
                }
                $value[] = $profile[0];
                $value[] = $profile[1];
                $value[] = $profile[2];
          }
      }

      $this->export($datas, $this->_outputFile);
      echo "输出文件路径: {$this->_outputFile} \n";
      echo '完结!!!'.PHP_EOL;
  }

  /**
   * show a status bar in the console
   *
   * <code>
   * for($x=1;$x<=100;$x++){
   *
   *     show_status($x, 100);
   *
   *     usleep(100000);
   *
   * }
   * </code>
   *
   * @param   int     $done   how many items are completed
   * @param   int     $total  how many items are to be done total
   * @param   int     $size   optional size of the status bar
   * @return  void
   *
   */
  public function show_status($done, $total, $size=30) {

      static $start_time;

      // if we go over our bound, just ignore it
      if($done > $total) return;

      if(empty($start_time)) $start_time=time();
      $now = time();

      $perc=(double)($done/$total);

      $bar=floor($perc*$size);

      $status_bar="\r[";
      $status_bar.=str_repeat("=", $bar);
      if($bar<$size){
          $status_bar.=">";
          $status_bar.=str_repeat(" ", $size-$bar);
      } else {
          $status_bar.="=";
      }

      $disp=number_format($perc*100, 0);

      $status_bar.="] $disp%  $done/$total";

      $rate = ($now-$start_time)/$done;
      $left = $total - $done;

      $elapsed = $now - $start_time;

      $status_bar.= " 用时: ".number_format($elapsed)." sec.";

      echo "$status_bar  ";

      flush();

      // when done, send a newline
      if($done == $total) {
          echo "\n";
      }

  }

  /**
   * 输出文件
   */
  public function export($datas, $path = '')
  {
      $obj = new \PHPExcel();
      $objSheet = $obj->setActiveSheetIndex(0);
      $col = 1;
      foreach ($datas as $idx => $lines) {
          $chr = 65;
          foreach ($lines as $i => $val) {
              $row = chr($chr + $i);
              $objSheet->setCellValue("{$row}{$col}", $val);
          }
          $col++;
      }

      $extensionType = $this->_getExtensionOnly($path);
      $objWriter = \PHPExcel_IOFactory::createWriter($obj, $extensionType);
      $objWriter->save($path);
  }


  /**
   * 测试一条记录
   */
  public function testOne($url, $word)
  {
      $content = $this->http($url);
      $result  = $this->valid($content, $word);
      var_dump($result);
  }


  /**
   * 通过扩展名获取文件类型
   */
  private function _getExtensionOnly($path)
  {
      $pathinfo = pathinfo($path);
      $extensionType = NULL;
      if (isset($pathinfo['extension'])) {
        switch (strtolower($pathinfo['extension'])) {
        	case 'xlsx':			//	Excel (OfficeOpenXML) Spreadsheet
        	case 'xlsm':			//	Excel (OfficeOpenXML) Macro Spreadsheet (macros will be discarded)
        	case 'xltx':			//	Excel (OfficeOpenXML) Template
        	case 'xltm':			//	Excel (OfficeOpenXML) Macro Template (macros will be discarded)
        		$extensionType = 'Excel2007';
        		break;
        	case 'xls':				//	Excel (BIFF) Spreadsheet
        	case 'xlt':				//	Excel (BIFF) Template
        		$extensionType = 'Excel5';
        		break;
        	case 'ods':				//	Open/Libre Offic Calc
        	case 'ots':				//	Open/Libre Offic Calc Template
        		$extensionType = 'OOCalc';
        		break;
        	case 'slk':
        		$extensionType = 'SYLK';
        		break;
        	case 'xml':				//	Excel 2003 SpreadSheetML
        		$extensionType = 'Excel2003XML';
        		break;
        	case 'gnumeric':
        		$extensionType = 'Gnumeric';
        		break;
        	case 'htm':
        	case 'html':
        		$extensionType = 'HTML';
        		break;
        	case 'csv':
        		// Do nothing
        		// We must not try to use CSV reader since it loads
        		// all files including Excel files etc.
        		break;
        	default:
        		$extensionType = 'Excel5';
        		break;
        }
    }

    return $extensionType;
  }


  /**
   * 校对函数
   */
  public function valid($content, $validWord)
  {
      // 转码成utf8
      $ret = preg_match('/charset=(.*?)>/is', $content, $matchs);
      if ($ret > 0 && !empty($matchs[1])) {
          $trans = trim($matchs[1], '/"\' ');
      }
      if (!empty($trans) && strlen($trans) < 20 && strtoupper($trans) !== 'UTF-8') {
          $content = iconv($trans, 'UTF-8', $content);
      }
      if (strpos($content, $validWord) !== false) {
          return true;
      }
      return  false;
  }


    /**
     * 获取的网络数据
     */
    public function http($url)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Paw/3.1 (Macintosh; OS X/10.11.6) GCDHTTPRequest');

        $cookie = './data/cookie'; //注意路径
        if (is_readable($cookie)) {
            $txt = file_get_contents($cookie);
            curl_setopt($ch, CURLOPT_COOKIE, $txt);
        }

        $result   = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $location = curl_getinfo($ch, CURLINFO_REDIRECT_URL);
        curl_close($ch);

        if ($httpCode == 302 || $httpCode == 301) {
            $result = $this->http($location);
        }
        return $result;
    }


    /**
     * 提取博主信息
     * @param  string 微博内容
     * @return {粉丝数, 博文数}
     */
    public function weibo($content = '')
    {
        $content = str_replace('\\', '', $content);
        $pattern = '/<div \s class=\"WB_info\">.*?<a \s href=\"\/\/(.*?)\" .*? >.*?<\/a>.*?<\/div>/ix';
        preg_match($pattern, $content, $matches);
        $url = $matches[1];
        if (empty($url)) {
            return array(0, 0, 0);
        }

        // http://weibo.com/u/5273816911
        $url = "http://{$url}";
        $subject = $this->http($url);
        if (empty($subject)) {
            return array(0, 0, 0);
        }
        $subject = str_replace('\\', '', $subject);
        $pattern = '/<strong class="W_f.*?">(.*?)<\/strong>/i';
        $ret = preg_match_all($pattern, $subject, $matches);
        if ($ret < 1) {
            return array(0, 0, 0);
        }
        $info = $matches[1]; // [关注, 粉丝, 博客]
        if (empty($info)) {
            return array(0, 0, 0);
        }
        return $info;
    }
}